const parser = require("@babel/parser");//将JS源码转换成语法树的函数
const traverse = require("@babel/traverse").default;//遍历AST的函数
const types = require("@babel/types");//操作节点的函数，比如判断节点类型，生成新的节点等:
const generator = require("@babel/generator").default;//将语法树转换为源代码的函数
const fs = require('fs');//const fs = require('fs')

//TODO 替换成当前fullpage中的信息

    AZsTZ.Buh = function() {
        var dhH = 2;
        for (; dhH !== 1;) {
            switch (dhH) {
                case 2:
                    return {
                        eDt: function(fHv) {
                            var gnz = 2;
                            for (; gnz !== 14;) {
                                switch (gnz) {
                                    case 5:
                                        gnz = hCm < iri.length ? 4 : 7;
                                        break;
                                    case 2:
                                        var jhl = '',
                                            iri = decodeURI('%0Dn*jlr%3CR%1EQQ%5Ds%7F%16%5EWJ\'m*jlw%0Dn*WSE?n*jlw5E%1AWF@%3C%5E*jlL#n*jGG7U%12%5D%5CL7n*jlw%0Dn*jSD7n%18U%5CN%0Dn*jlw%0Dn*jlw%0Dn*jlw0D*jlw%0Dn*jWQ#_%06@Aw%0Dn%00%5Ba%5D!Y%1ASlw%0Dn*jlw%0Dn*jlw%0Do%13WFw%0Dn%1BVXL0D*jlw?U%1ASFA%0Dn*jlw%0DS%1CU@j%3CT%11uFw%0Dn%04F%5D%5D%3CD%0DDWw%0Dn*j');
                                        gnz = 1;
                                        break;
                                    case 1:
                                        var hCm = 0,
                                            kxC = 0;
                                        gnz = 5;
                                        break;
                                    case 4:
                                        gnz = kxC === fHv.length ? 3 : 9;
                                        break;
                                    case 8:
                                        hCm++, kxC++;
                                        gnz = 5;
                                        break;
                                    case 3:
                                        kxC = 0;
                                        gnz = 9;
                                        break;
                                    case 9:
                                        jhl += String.fromCharCode(iri.charCodeAt(hCm) ^ fHv.charCodeAt(kxC));
                                        gnz = 8;
                                        break;
                                    case 7:
                                        jhl = jhl.split('^');
                                        return function(lnd) {
                                            var mdk = 2;
                                            for (; mdk !== 1;) {
                                                switch (mdk) {
                                                    case 2:
                                                        return jhl[lnd];
                                                        break;
                                                }
                                            }
                                        };
                                        break;
                                }
                            }
                        }('S0t42)')
                    };
                    break;
            }
        }
    }();
    AZsTZ.ChB = function() {
        var nlX = 2;
        for (; nlX !== 1;) {
            switch (nlX) {
                case 2:
                    return {
                        oXN: function pSe(qKb, rKK) {
                            var ssl = 2;
                            for (; ssl !== 10;) {
                                switch (ssl) {
                                    case 4:
                                        tnT[(uWj + rKK) % qKb] = [];
                                        ssl = 3;
                                        break;
                                    case 13:
                                        vRm -= 1;
                                        ssl = 6;
                                        break;
                                    case 9:
                                        var wQQ = 0;
                                        ssl = 8;
                                        break;
                                    case 8:
                                        ssl = wQQ < qKb ? 7 : 11;
                                        break;
                                    case 12:
                                        wQQ += 1;
                                        ssl = 8;
                                        break;
                                    case 6:
                                        ssl = vRm >= 0 ? 14 : 12;
                                        break;
                                    case 1:
                                        var uWj = 0;
                                        ssl = 5;
                                        break;
                                    case 2:
                                        var tnT = [];
                                        ssl = 1;
                                        break;
                                    case 3:
                                        uWj += 1;
                                        ssl = 5;
                                        break;
                                    case 14:
                                        tnT[wQQ][(vRm + rKK * wQQ) % qKb] = tnT[vRm];
                                        ssl = 13;
                                        break;
                                    case 5:
                                        ssl = uWj < qKb ? 4 : 9;
                                        break;
                                    case 7:
                                        var vRm = qKb - 1;
                                        ssl = 6;
                                        break;
                                    case 11:
                                        return tnT;
                                        break;
                                }
                            }
                        }(21, 7)
                    };
                    break;
            }
        }
    }();
    AZsTZ.DpY = function() {
        return typeof AZsTZ.Buh.eDt === 'function' ? AZsTZ.Buh.eDt.apply(AZsTZ.Buh, arguments) : AZsTZ.Buh.eDt;
    };
    AZsTZ.ECM = function() {
        return typeof AZsTZ.ChB.oXN === 'function' ? AZsTZ.ChB.oXN.apply(AZsTZ.ChB, arguments) : AZsTZ.ChB.oXN;
    };
function AZsTZ() {}
//TODO 替换成当前初始方法
// var init_func_name = "AEOAb";
var init_func_name = "AZsTZ";
//TODO 替换成当前数组方法名（DAi）
// var Array_func_name = "DCY";
var Array_func_name = "DpY";
//TODO 替换成当前空数组方法名（EMf）
// var Array2_func_name = "EFd";
var Array2_func_name = "ECM";



var Array_func = function (arg) {
    let func_name1 = init_func_name + "." + Array_func_name;
    let value1 = eval(func_name1 + "(" + arg +")");
    return value1
};

var Array2_func = function (arg1,arg2) {
    let func_name2 = init_func_name + "." + Array2_func_name;
    let value2 = eval(func_name2 + "()["+ arg1 +"]["+ arg2 +"]");
    return value2
};
var name_Array = [];

const visitor = {
    VariableDeclaration:{
        enter: [get_name_Array,del_DAi]
    },
    CallExpression:{
        enter: [replace_name_Array,replace_DAi]
    },
    StringLiteral:{
        enter: [replace_unicode]
    },
    ForStatement:{
      enter: [replaceForStatement]
    }
};
function replace_unicode(path){
    delete path.node.extra;
}
function replace_DAi(path){
    var node = path.node;
    if(node.callee == undefined || node.callee.property ==undefined )
      return;
    if (node.callee.property.name == Array_func_name){
        let arg = node.arguments[0].value;
        let value = Array_func(arg);
        PathToLiteral(path,value)
    }
}
function get_name_Array(path){
  var node = path.node;
  if (node.declarations == undefined
      || node.declarations.length !=3
      || node.declarations[0].init == undefined
      || node.declarations[0].init.property == undefined )
    return;
  if (node.declarations[0].init.property.name != Array_func_name)
    return;
  let name1 = node.declarations[0].id.name;
  let name2 = node.declarations[2].id.name;
  name_Array.push(name1,name2);
}
function replace_name_Array(path) {
    var node = path.node;
    if(node.callee == undefined || node.callee.name ==undefined )
      return;
    if (name_Array.indexOf(node.callee.name) == -1)
      return;
    let arg = node.arguments[0].value;
    let value = Array_func(arg);
    PathToLiteral(path,value)
}
function PathToLiteral(path,value){
      switch (typeof value) {
          case 'boolean':
              path.replaceWith(types.booleanLiteral(value));
              break;
          case 'string':
              path.replaceWith(types.stringLiteral(value));
              break;
          case 'number':
              path.replaceWith(types.numericLiteral(value));
              break;
          default:
              console.log("出现其他类型" + value + "类型:" +typeof value);
              console.log(value);
              break
      }
}
function check_DAi(declaration) {
    if (declaration.init == undefined || declaration.init.property == undefined)
        return ;
    if (declaration.init.property.name == Array_func_name)
        return true;
}
function del_DAi(path) {
    var node = path.node;
    var arrNode = node.declarations;
    for(var i=0; i<arrNode.length; i++){
        if (check_DAi(arrNode[i])== true){
            path.remove();
            var nextPath = path.getNextSibling();
            nextPath.remove();//删除下个节点
            var nnextPath = nextPath.getNextSibling();
            nnextPath.remove();//删除下下个节点
            break
        }
    }
}
function replaceForStatement(path) {
    var node = path.node;
    var prevSiblingPath = path.getPrevSibling();
    if (prevSiblingPath.container ==undefined ||
        prevSiblingPath.container[0].declarations ==undefined ||
        prevSiblingPath.container[0].declarations[0].init ==undefined ||
        prevSiblingPath.container[0].declarations[0].init.object ==undefined ||
        prevSiblingPath.container[0].declarations[0].init.object.object ==undefined
    )
      return;
    if (prevSiblingPath.container[0].declarations[0].init.object.object.callee.property.name != Array2_func_name)
        return;
    var body = node.body.body;
    if(!types.isSwitchStatement(body[0] ||
        !types.isIdentifier(body[0].discriminant)))
        return;

    var swithStm = body[0];

    var arg = prevSiblingPath.container[0].declarations[0].init;
    let init_arg_f = arg.object.property.value;
    let init_arg_s = arg.property.value;

    var init_arg = Array2_func(init_arg_f,init_arg_s);
    let break_arg_f = node.test.right.object.property.value;
    let break_arg_s = node.test.right.property.value;
    var break_init = Array2_func(break_arg_f,break_arg_s);

    var caseList = swithStm.cases;
    var resultBody =[];

    // TODO, 此循环方式有问题，即case是必须按顺序执行的（恰巧目前混淆也是这样做的，因此出现没问题）
    for (var i=0;i<caseList.length;i++){
        for (;init_arg !== break_init;)
            {
                var case_arg_f = caseList[i].test.object.property.value;
                var case_arg_s = caseList[i].test.property.value;
                var case_init = Array2_func(case_arg_f,case_arg_s);
                if (init_arg == case_init){
                    var targetBody = caseList[i].consequent;
                    if (types.isBreakStatement(targetBody[targetBody.length - 1]) &&
                        types.isExpressionStatement(targetBody[targetBody.length - 2]) &&
                        targetBody[targetBody.length - 2].expression.right.object.object.callee.object.name == init_func_name){
                        var change_arg_f = targetBody[targetBody.length - 2].expression.right.object.property.value;
                        var change_arg_s = targetBody[targetBody.length - 2].expression.right.property.value;
                        init_arg = Array2_func(change_arg_f,change_arg_s);
                        targetBody.pop();
                        targetBody.pop();
                    }
                    else if (types.isBreakStatement(targetBody[targetBody.length - 1])){
                        targetBody.pop();
                    }
                    resultBody = resultBody.concat(targetBody);
                    break;
                }else{
                    break;
                }

            }

    }
	path.replaceWithMultiple(resultBody);
	prevSiblingPath.remove();
}
var verName = "D:\\python_workspace\\my_geetest_crack\\ast_js\\gct\\gct.raw";
// var verName = "slide.7.7.6";
var sourceFile = verName + '.js';
var targetFile = verName + "_11.js";
//TODO 替换成当前fullpage名字
var jscode = fs.readFileSync(sourceFile, {
    encoding: "utf-8"
});
let ast = parser.parse(jscode);
traverse(ast,visitor);
let {code} = generator(ast,{jsescOption:{
	//自动转义中文
		minimal:true
	}});
//TODO 替换成输出fullpage名字
fs.writeFile(targetFile, code, (err)=>{});
console.log('......FINISHED!');
